package com.gsi.webstore.platform.storefront.pipelet.inventory;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.gsi.webstore.platform.adapter.inventory.adjustment.capi.GSIAdvancedInventoryAdjustmentService;
import com.gsi.webstore.platform.adapter.inventory.adjustment.internal.GSIAdvancedInventoryAdjustmentServiceResolver;
import com.gsi.webstore.platform.adapter.storelocator.capi.StoreLocatorManager;
import com.gsi.webstore.platform.adapter.storelocator.internal.client.data.Storefront;
import com.intershop.beehive.core.capi.component.ComponentMgr;
import com.intershop.beehive.core.capi.domain.Domain;
import com.intershop.beehive.core.capi.log.Logger;
import com.intershop.beehive.core.capi.naming.NamingMgr;
import com.intershop.beehive.core.capi.pipeline.Pipelet;
import com.intershop.beehive.core.capi.pipeline.PipelineDictionary;
import com.intershop.beehive.core.capi.pipeline.PipeletExecutionException;
import com.intershop.beehive.core.capi.pipeline.PipelineInitializationException;
import com.intershop.beehive.bts.capi.orderprocess.ProductLineItem;
import com.intershop.beehive.bts.capi.orderprocess.basket.Basket;
import com.intershop.component.organization.capi.Organization;
import com.intershop.beehive.core.capi.request.Request;
import com.intershop.beehive.xcs.capi.product.Product;
import com.intershop.beehive.xcs.capi.product.ProductMgr;
import com.intershop.beehive.xcs.common.ProductRef;

/**
 * Creates an inventory adjustment.
 */
public class GSIAdjustInventory extends Pipelet
{
    private ProductMgr productMgr;
    private StoreLocatorManager storeLocatorMgr;
    private static final String STOREFRONT_ID_ATTRIBUTE = "STORE_ID";
    private static final String FULFILLMENT_METHOD_ATTRIBUTE = "MC_FULFILLMENT_METHOD";
    private static final String ISPU = "ISPU";
    private static final String PRODUCT_ISPU_ATTRIBUTE = "Multichannel / In Store Pickup Enabled";
    private static final String PRODUCT_SFS_ATTRIBUTE = "Multichannel / Ship From Store Enabled";

    /**
     * Constant used to access the pipeline dictionary with key 'Basket'
     */
    public static final String DN_BASKET = "Basket";
    /**
     * Constant used to access the pipeline dictionary with key 'Organization'
     */
    public static final String DN_ORGANIZATION = "Organization";
    /**
     * Constant used to access the pipeline dictionary with key 'CurrentRequest'
     */
    public static final String DN_CURRENT_REQUEST = "CurrentRequest";

    /**
     * The pipelet's execute method is called whenever the pipelets gets
     * executed in the context of a pipeline and a request. The pipeline
     * dictionary valid for the currently executing thread is provided as a
     * parameter.
     * 
     * @param dict
     *            The pipeline dictionary to be used.
     * @throws PipeletExecutionException
     *             Thrown in case of severe errors that make the pipelet execute
     *             impossible (e.g. missing required input data).
     */
    public int execute(PipelineDictionary dict)
    throws PipeletExecutionException {        
        // lookup 'CurrentRequest' in pipeline dictionary
        Request currentRequest = (Request)dict.get(DN_CURRENT_REQUEST);
        if (null == currentRequest)
        {
            throw new PipeletExecutionException(
                            "Mandatory input parameter 'CurrentRequest' not available in pipeline dictionary.");
        
        }
        
        // lookup 'Organization' in pipeline dictionary
        Organization organization = (Organization)dict.get(DN_ORGANIZATION);
        if (null == organization)
        {
            throw new PipeletExecutionException(
                            "Mandatory input parameter 'Organization' not available in pipeline dictionary.");
        
        }
        
        // lookup 'Basket' in pipeline dictionary
        Basket basket = (Basket)dict.get(DN_BASKET);
        if (null == basket)
        {
            throw new PipeletExecutionException("Mandatory input parameter 'Basket' not available in pipeline dictionary.");
        
        }
        
        final Domain prefDomain = organization.getOwningDomain();
        ComponentMgr componentMgr = NamingMgr.getManager(ComponentMgr.class);
        final GSIAdvancedInventoryAdjustmentServiceResolver invAdjServiceResolver = componentMgr.getComponent( "advancedInventoryAdjustmentServiceResolver");
        
        if (invAdjServiceResolver == null) {
            throw new PipeletExecutionException("Mandatory 'GSIAdvancedInventoryAdjustmentServiceResolver' not available from Component Framework.");
        }
        
        GSIAdvancedInventoryAdjustmentService invAdjService = null;
        
        try {
            invAdjService = invAdjServiceResolver.getInventoryAdjustmentService(prefDomain);
        } catch (Exception e) {
            Logger.error(this, e.getMessage());
        }
        
        if (invAdjService == null)
        {
            throw new PipeletExecutionException("Mandatory 'GSIAdvancedInventoryAdjustmentService' not available for domain " + prefDomain.getDomainName());
        }
        
        Iterator<ProductLineItem> lineItemsIterator = basket.createProductLineItemsIterator();
        String localeID = currentRequest.getLocale().getLocaleID();
        Map<String, Integer> adjustmentQtyMap = new HashMap<String, Integer>();
        while (lineItemsIterator.hasNext()) {
            ProductLineItem lineItem = lineItemsIterator.next();
            String lineItemFulfillmentMethod = (String)lineItem.getAttribute(FULFILLMENT_METHOD_ATTRIBUTE);
            Long lineItemStoreId = (Long)lineItem.getAttribute(STOREFRONT_ID_ATTRIBUTE);
            
            if (ISPU.equals(lineItemFulfillmentMethod)) {
                ProductRef productRef = lineItem.getDefinitionProductRef();
                Product product = productMgr.getProductByProductRef(productRef);
                Boolean isProductISPUEnabled = product.getBoolean(PRODUCT_ISPU_ATTRIBUTE);
                Boolean isProductSFSEnabled = product.getBoolean(PRODUCT_SFS_ATTRIBUTE);
                if ((isProductISPUEnabled != null && isProductISPUEnabled) && (isProductSFSEnabled != null && isProductSFSEnabled)) {
                    Storefront storefront = storeLocatorMgr.getStorefront(lineItemStoreId, localeID);
                    if (storefront != null &&
                        storefront.isInStorePickUpEligible() &&
                        storefront.isSFSEligible()) {
                        adjustmentQtyMap.put(productRef.getProductSKU(), new Integer(-lineItem.getQuantity().getValue().intValue()));
                    }
                 }
            }
        }
        
        invAdjService.inventoryAdjustment(adjustmentQtyMap);

        return PIPELET_NEXT;
    }
    
    public void init() throws PipelineInitializationException {
        productMgr = (ProductMgr)NamingMgr.getInstance().lookupManager(ProductMgr.REGISTRY_NAME);
        storeLocatorMgr = (StoreLocatorManager)NamingMgr.getInstance().lookupManager(StoreLocatorManager.REGISTRY_NAME);
    }
}